package com.ibeeking.found.upms.b.rest.service.impl;

import com.ibeeking.found.common.entity.TenantDTO;
import com.ibeeking.found.upms.b.rest.service.IOpenUrlRelationService;
import com.ibeeking.found.upms.b.rest.service.IOpenUrlService;
import com.ibeeking.found.upms.b.rest.service.IOpenUserService;
import com.ibeeking.found.common.base.BaseDO;
import com.ibeeking.found.common.config.feign.GlobalClient;
import com.ibeeking.found.common.config.secret.RsaConfig;
import com.ibeeking.found.common.constants.GlobalConstant;
import com.ibeeking.found.common.entity.LoginOpenUserDTO;
import com.ibeeking.found.common.enums.PublishStatusEnum;
import com.ibeeking.found.common.utils.UserUtils;
import com.ibeeking.found.upms.service.common.bo.OpenUrlBO;
import com.ibeeking.found.upms.service.common.bo.OpenUrlRelationBO;
import com.ibeeking.found.upms.service.common.bo.OpenUserBO;
import com.ibeeking.found.upms.service.common.dos.OpenUserDO;
import com.ibeeking.found.upms.service.common.param.OpenUserParam;
import com.ibeeking.found.upms.service.common.po.OpenUserPO;
import com.ibeeking.found.upms.service.common.query.OpenUserPageQuery;
import com.ibeeking.found.upms.service.common.vo.OpenUserPageVO;
import com.ibeeking.found.upms.service.common.vo.OpenUserVO;
import com.ibeeking.found.upms.service.mapper.OpenUserMapper;
import com.ibeeking.nematos.core.utils.SpringBeanUtil;
import com.ibeeking.nematos.exception.BusinessException;
import com.ibeeking.nematos.utils.bean.BeanUtil;
import com.ibeeking.nematos.utils.data.Collections3;
import com.ibeeking.nematos.utils.data.StringUtils;
import com.ibeeking.nematos.utils.encryption.EncryptUtils;
import com.ibeeking.nematos.utils.id.IdGen;
import com.ibeeking.nematos.utils.result.ResponseResult;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @ClassName OpenUserServiceImpl
 * @Description
 * @Author ibeeking
 * @Date 2021-03-31 16:56
 **/
@Service
public class OpenUserServiceImpl implements IOpenUserService {

    @Resource
    private OpenUserMapper openUserMapper;
    @Resource
    private RsaConfig rsaConfig;
    @Resource
    private IOpenUrlRelationService openUrlRelationServiceImpl;
    @Resource
    private IOpenUrlService openUrlServiceImpl;
    @Resource
    private GlobalClient globalClient;

    @Override
    public Page<OpenUserPageVO> pageList(OpenUserPageQuery query) {
        LambdaQueryWrapper<OpenUserDO> queryWrapper = new LambdaQueryWrapper<>(OpenUserDO.class)
                .orderByDesc(BaseDO::getCreateTime)
                .eq(null != query.getPublishStatus(), OpenUserDO::getPublishStatus, query.getPublishStatus())
                .eq(StringUtils.isNotBlank(query.getAppId()), OpenUserDO::getAppId, query.getAppId())
                .like(StringUtils.isNotBlank(query.getName()), OpenUserDO::getName, query.getName());

        Page<OpenUserDO> page = openUserMapper.selectPage(new Page<>(query.getPageNum(), query.getPageSize()), queryWrapper);
        return BeanUtil.convertPage(page, OpenUserPageVO.class);
    }

    @Override
    public Boolean add(OpenUserParam param, String tenantId) {
        OpenUserDO openUserDO = BeanUtil.convertBean(param, OpenUserDO.class);
        openUserDO.setCreateBy(UserUtils.getUserId());
        openUserDO.setCreateTime(LocalDateTime.now());
        openUserDO.setModifyTime(LocalDateTime.now());
        openUserDO.setAppId(IdGen.randomStr(18));
        ResponseResult<List<Integer>> responseResult = globalClient.queryTenantIds();
        if (null == responseResult || Collections3.isEmpty(responseResult.getData())) {
            return false;
        }
        while (!checkUnique(responseResult.getData(), openUserDO.getAppId())) {
            openUserDO.setAppId(IdGen.randomStr(18));
        }
        openUserDO.setAppSecret(EncryptUtils.AesEncrypt.encrypt(IdGen.randomStr(18), rsaConfig.getSecretKey()));
        openUserDO.setReadSecret(openUserDO.getAppSecret());
        return openUserMapper.insert(openUserDO) > 0;
    }

    @Override
    public Boolean modify(OpenUserParam param) {
        OpenUserBO openUserBO = getBean().queryById(param.getId());
        if (PublishStatusEnum.ENABLE.getValue().equals(openUserBO.getPublishStatus())) {
            throw new BusinessException("请先禁用后再修改");
        }
        OpenUserDO openUserDO = BeanUtil.convertBean(param, OpenUserDO.class);
        openUserDO.setModifyBy(UserUtils.getUserId());
        openUserDO.setModifyTime(LocalDateTime.now());
        return openUserMapper.updateById(openUserDO) > 0;
    }

    @Override
    public OpenUserVO view(Long id) {
        OpenUserBO openUserBO = getBean().queryById(id);
        if (null == openUserBO) {
            return null;
        }
        OpenUserVO openUserVO = BeanUtil.convertBean(openUserBO, OpenUserVO.class);
        openUserVO.setAppSecret(GlobalConstant.ENCRYPT);
        return openUserVO;
    }

    @Override
    public OpenUserBO queryById(Long id) {
        OpenUserDO userDO = openUserMapper.selectById(id);
        if (null == userDO) {
            return null;
        }
        return BeanUtil.convertBean(userDO, OpenUserBO.class);
    }

    @Override
    public Boolean changeStatus(Long id, Integer status) {
        OpenUserDO openUserDO = new OpenUserDO();
        openUserDO.setId(id);
        openUserDO.setPublishStatus(status);
        openUserDO.setModifyBy(UserUtils.getUserId());
        openUserDO.setModifyTime(LocalDateTime.now());
        return openUserMapper.updateById(openUserDO) > 0;
    }

    @Transactional(rollbackFor = {Exception.class})
    @Override
    public Boolean del(Long id) {
        OpenUserBO openUserBO = getBean().queryById(id);
        if (PublishStatusEnum.ENABLE.getValue().equals(openUserBO.getPublishStatus())) {
            throw new BusinessException("请先禁用后再删除");
        }
        openUserMapper.deleteById(id);
        openUrlRelationServiceImpl.delByUserId(id);
        return true;
    }

    @Override
    public Boolean resetSecret(Long id, String tenantId) {
        OpenUserDO openUserDO = new OpenUserDO();
        openUserDO.setId(id);
        openUserDO.setAppSecret(EncryptUtils.AesEncrypt.encrypt(tenantId.concat("_").concat(IdGen.randomStr(18)), rsaConfig.getSecretKey()));
        openUserDO.setReadSecret(openUserDO.getAppSecret());
        openUserDO.setModifyTime(LocalDateTime.now());
        return openUserMapper.updateById(openUserDO) > 0;
    }

    @Override
    public String showSecret(Long id) {
        OpenUserBO openUserBO = getBean().queryById(id);
        if (null == openUserBO || GlobalConstant.ENCRYPT.equals(openUserBO.getReadSecret())) {
            return GlobalConstant.ENCRYPT;
        }
        OpenUserDO openUserDO = new OpenUserDO();
        openUserDO.setId(id);
        openUserDO.setReadSecret(GlobalConstant.ENCRYPT);
        openUserDO.setModifyTime(LocalDateTime.now());
        openUserMapper.updateById(openUserDO);
        return openUserBO.getReadSecret();
    }

    @Override
    public LoginOpenUserDTO queryLoginUser(String appId) {
        ResponseResult<List<Integer>> responseResult = globalClient.queryTenantIds();
        if (null == responseResult || Collections3.isEmpty(responseResult.getData())) {
            return null;
        }
        OpenUserPO openUserPO = openUserMapper.queryByAppId(responseResult.getData(), appId);
        Integer tenantId = openUserPO.getTenantId();
        LoginOpenUserDTO loginOpenUserDTO =  BeanUtil.convertBean(openUserPO, LoginOpenUserDTO.class);
        if(tenantId!=null) {
            TenantDTO tenantDTO = queryTenantById(tenantId);
            if(tenantDTO != null){
                loginOpenUserDTO.setIndustry(tenantDTO.getIndustry());
            }
        }
        return loginOpenUserDTO;
    }

    @Override
    public List<String> queryApis(Long userId) {
        List<OpenUrlRelationBO> openUrlRelationBos = openUrlRelationServiceImpl.queryByUserId(userId);
        if (Collections3.isEmpty(openUrlRelationBos)) {
            return Collections.emptyList();
        }
        List<OpenUrlBO> openUrlBos = openUrlServiceImpl.queryByIds(openUrlRelationBos.parallelStream().map(OpenUrlRelationBO::getOpenUrlId).distinct().collect(Collectors.toList()));
        if (Collections3.isEmpty(openUrlBos)) {
            return Collections.emptyList();
        }
        return openUrlBos.parallelStream().filter(openUrlBO -> PublishStatusEnum.ENABLE.getValue().equals(openUrlBO.getPublishStatus())).map(OpenUrlBO::getUrl).collect(Collectors.toList());
    }

    private static IOpenUserService getBean() {
        return SpringBeanUtil.getBean(IOpenUserService.class);
    }

    private Boolean checkUnique(List<Integer> tenantIds, String appId) {
        List<Long> ids = openUserMapper.checkUnion(tenantIds, appId);
        return Collections3.isEmpty(ids);
    }


    private TenantDTO queryTenantById(Integer tenantId) {
        ResponseResult<TenantDTO> responseResult = globalClient.queryTenantById(tenantId);
        if (null == responseResult || null == responseResult.getData()) {
            throw new BusinessException("租户不存在");
        }
        return responseResult.getData();
    }
}
